package com.dlc.felear.xiaoensale.helper;

import android.util.Log;

import com.dlc.felear.xiaoensale.constant.Constant;
import com.dlc.felear.xiaoensale.dlc_serial_port.DlcSerialPortClient;
import com.dlc.felear.xiaoensale.utils.HexUtil;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;

public class IoOutHelper {
    private static final String TAG="IoInputHelper";
    private static final int WAITDELAY=30;
    private ScheduledExecutorService scheduledThreadPool;
    private Map<Byte, Byte> outputMaps ;
    private Map<Byte, Byte> outputMapsLast ;
//    private IoOutputCallback ioOutputCallback;
    private ArrayBlockingQueue<byte[]> mQueue;
    private final String serialNum= Constant.TTYS1;
    public IoOutHelper(){
        outputMaps = new HashMap<>();
        mQueue = new ArrayBlockingQueue<>(20);
        outputMapsLast = new HashMap<>();
        scheduledThreadPool = new ScheduledThreadPoolExecutor(3);
        loopSendCmd();
    }


    public Map<Byte, Byte> getOutputMaps() {
        return outputMaps;
    }

    public byte getIoStatus(byte num){
        if(!outputMaps.containsKey(num)){
            return 0;
        }
        return outputMaps.get(num);
    }

    /**
     * 记录输入IO的状态
     *
     * @param cmd
     */
    public void ouputStatus(final byte[] cmd) {
        scheduledThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 3; i < cmd.length - 2; i++) {
                    for (int j = 0; j < 8; j++) {
                        int key = 8 * (i - 3) + j + (cmd[0] - 2) * 26;
                        byte tt = getBit(cmd[i], j);
                        outputMaps.put((byte) key, tt);
                    }
                }
                listence();
            }
        });
    }

    /**
     * 添加指令到发送队列
     *
     * @param data
     */
    public void addCmdToQueque(byte[] data) {
        try {
            if (data != null) {
                mQueue.offer(data);
            }
        } catch (Exception e) {

        }
    }

    /**
     * 监听输入IO状态
     */
    private void listence() {
        scheduledThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    if (outputMapsLast.isEmpty()) {
                        outputMapsLast.putAll(outputMaps);
                    }
                    for (byte b : outputMaps.keySet()) {
                        byte c_value = getMapValue(outputMaps, b);
                        byte l_value = getMapValue(outputMapsLast, b);
                        if (c_value != l_value && c_value == 0) {
                            ioTrigger(b);
                        }
                    }
                    outputMapsLast.clear();
                    outputMapsLast.putAll(outputMaps);
                } catch (Exception e) {
                    Log.e(TAG, e.getMessage());
                }
            }
        });
    }

    private void ioTrigger(int index) {
        Log.e(TAG, "触发开关:" + index);

    }


    /**
     * 获取map的值
     *
     * @param map
     * @param key
     * @return
     */
    private byte getMapValue(Map<Byte, Byte> map, byte key) {
        if (!map.containsKey(key)) {
            return 0;
        }
        return map.get(key);
    }



    private byte getBit(byte b, int index) {
        return (byte) ((b >> index) & 0x01);
    }



    public interface IoOutputCallback{
        void ioOutputChange(byte num);
    }

    /**
     * 发送指令
     */
    private void loopSendCmd() {
        scheduledThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        byte[] orders = null;
                        // take位阻塞方法，取不到消息时会阻塞当前线程
                        while ((orders = mQueue.take()) != null) {
                            sendCmd(orders);
                            // 睡眠，防止数据粘包
                            Thread.sleep(WAITDELAY);
                        }
                    } catch (Exception e) {

                    }
                }
            }
        });
    }

    /**
     * 发送指令到串口
     *
     * @param data
     */
    private void sendCmd(byte[] data) {
        DlcSerialPortClient.getInstance().send(serialNum, data);
    }
}
